import argparse
from pathlib import Path
import numpy as np
import open3d as o3d


def main() -> None:
    p = argparse.ArgumentParser(description="Open3D 查看 PLY 点云或网格（支持默认翻转视角）")
    p.add_argument("--file", required=True, help="PLY 文件路径")
    p.add_argument("--flip_view", action="store_true", help="将视角水平翻转（等效Z轴180°），默认启用", default=True)
    args = p.parse_args()

    path = Path(args.file)
    if not path.exists():
        raise SystemExit(f"文件不存在: {path}")

    geom = None
    mesh = o3d.io.read_triangle_mesh(str(path))
    if mesh.has_triangles():
        mesh.compute_vertex_normals()
        geom = mesh
    else:
        pcd = o3d.io.read_point_cloud(str(path))
        if not pcd.is_empty():
            geom = pcd

    if geom is None:
        raise SystemExit("无法读取为网格或点云。")

    vis = o3d.visualization.Visualizer()
    vis.create_window(window_name="Viewer", width=1280, height=800, visible=True)
    vis.add_geometry(geom)
    vis.poll_events(); vis.update_renderer()
    vc = vis.get_view_control()

    bbox = geom.get_axis_aligned_bounding_box()
    center = bbox.get_center()
    vc.set_lookat(center)

    # 水平翻转视角（等效绕Z轴180°），便于默认看到物体正面
    if args.flip_view:
        # 兼容旧版 Open3D：没有 get_front/get_up，用默认方向近似水平翻转
        try:
            front = np.array(vc.get_front())
            up = np.array(vc.get_up())
            if np.linalg.norm(front) > 0:
                vc.set_front((-front).tolist())
            vc.set_up(up.tolist())
        except Exception:
            # 退化方案：绕Z轴旋转180度视角
            try:
                vc.rotate(640, 0)  # 近似水平旋转
                vc.rotate(640, 0)
            except Exception:
                pass

    # 调整缩放以适配窗口
    try:
        extent = np.linalg.norm(bbox.get_max_bound() - bbox.get_min_bound())
        if extent > 0:
            # Open3D 约定：较小数值=更近。这里给一个经验缩放
            vc.set_zoom(0.8)
    except Exception:
        pass

    vis.run()
    vis.destroy_window()


if __name__ == "__main__":
    main()


